﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Collections;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
using Microsoft.TeamFoundation.Framework.Common;


namespace TFSFileTextSearch
{
    public partial class frmPrincipal : Form
    {
        TfsTeamProjectCollection server;
        bool cancelSearch = false;

        public frmPrincipal()
        {
            InitializeComponent();
        }

        private void frmPrincipal_Load(object sender, EventArgs e)
        {
            lblStatus.Text = "";
            var servers = RegisteredTfsConnections.GetConfigurationServers();
            foreach(var srv in servers)
            {
                cbServer.Items.Add(srv.Uri);
            }
        }


        private void btnConecta_Click(object sender, EventArgs e)
        {
            if (cbServer.SelectedIndex == -1)
            {
                MessageBox.Show("Please select a TFS Server");
                return;
            }

            lblStatus.Text = "Connecting to server...";
            toolStrip.Refresh();

            if (txtUser.Text != "")
            {
                NetworkCredential user = new NetworkCredential(txtUser.Text, txtPassword.Text); 
                server = new TfsTeamProjectCollection(new Uri(cbServer.Text), user);
            }
            else
            {
                server = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(cbServer.Text));
            }

            try
            {
                server.Connect(ConnectOptions.None);
            }
            catch (Exception ex)
            {
                MessageBox.Show("TFS Connect Error: " + ex.Message); 
                lblStatus.Text = "Error connecting to server."; 
                return;
            } 
            lblStatus.Text = "Connected to server.";

            Uri configurationServerUri = new Uri(cbServer.Text);

            TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(configurationServerUri);

            var configServerNode = configurationServer.CatalogNode;

            var collection = configServerNode.QueryChildren(new Guid[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None); 

            cbCollection.Items.Clear(); 
            foreach (var col in collection)
            {
                cbCollection.Items.Add(col.Resource.DisplayName);
            }
            cbCollection.SelectedIndex = 0;

        }

        private void cbCollection_SelectedIndexChanged(object sender, EventArgs e)
        {
            cbProjetos.DataSource = ListProjects();
        }

        public IEnumerable ListProjects()
        {
            var workItemStore = new WorkItemStore(server);
            var projectList = (from Project pr in workItemStore.Projects select pr.Name).ToList();

            return projectList;
        }


        private void btnBusca_Click(object sender, EventArgs e)
        {
            if (txtSearch.Text == string.Empty)
            {
                return;
            }

            if (lstFolder.SelectedItems.Count == 0)
            {
                MessageBox.Show("Please select a folder!");
                return;
            }

            cancelSearch = false;
            EnableButtons(false);
            

            List<string> folderSelecionado = new List<string>();
            foreach (var f in lstFolder.SelectedItems)
            {
                folderSelecionado.Add(f.ToString());
            }

            SearchText("$/"+cbProjetos.Text, "*.*", txtSearch.Text,folderSelecionado.ToArray());
            
        }

        private void EnableButtons(bool EnableDisable)
        {
            btnConect.Enabled = EnableDisable;
            btnSearch.Enabled = EnableDisable;
            btnAddResults.Enabled = EnableDisable;
            btnClearResults.Enabled = EnableDisable;
            btnExportXML.Enabled = EnableDisable;
            btnClose.Enabled = EnableDisable;
        }

        void SearchText(string RootNode, string Pattern, string Texto, string[] diretorios)
        {
            VersionControlServer vcs = (VersionControlServer)server.GetService(typeof(VersionControlServer));

            if (diretorios == null)
            {
                var pastas = vcs.GetExtendedItems(RootNode + "/*.*", DeletedState.NonDeleted, ItemType.Folder);

                lstFolder.Items.Clear();
                foreach (var dir in pastas)
                {
                    if (dir.IsBranch || dir.SourceServerItem.IndexOf("-V") != -1)
                    {
                        continue;
                    }
                    if (dir.SourceServerItem.ToUpper() == RootNode.ToUpper())
                    {
                        continue;
                    }
                    lstFolder.Items.Add(dir.SourceServerItem);
                }
                return;
            }

            List<string> arquivoEncontrado = new List<string>();
            lstSearchResult.Items.Clear();

            foreach(var dir in diretorios)
            {
                if (cancelSearch)
                {
                    break;
                }

                var arquivos = vcs.GetItems(dir+"/"  + Pattern, RecursionType.Full);

                var arquivosLer = new List<Item>();

                foreach (Item p in arquivos.Items)
                {
                    if (cancelSearch)
                    {
                        break;
                    }

                    if (p.ItemType == ItemType.File && !p.IsBranch && p.DeletionId == 0)
                    {
                        arquivosLer.Add(p);
                    }
                }

                int skip = 0;
                int take = 100;
                int qtdThread = arquivosLer.Count/take;

                progressBar.Maximum = arquivosLer.Count;

                while (true)
                {
                    if (cancelSearch)
                    {
                        break;
                    }

                    var arq = arquivosLer.Skip(skip).Take(take).ToList();
                    if (arq.Count == 0)
                    {
                        break;
                    }
                    var thread = new Thread(new ParameterizedThreadStart(ProcessaArquivos));
                    thread.Start(new ParametroThread() { parametroTexto = Texto, parametroArquivos = arq });
                    skip += take;
                }
                lblFolder.Text = dir;
                lblFolder.Refresh();
            }
            return; 
        }

        void ProcessaArquivos(object parametro)
        {
            var Texto = ((ParametroThread)parametro).parametroTexto.ToLower();
            var arquivos = ((ParametroThread)parametro).parametroArquivos;

            foreach (Item p in arquivos)
            {
                if (cancelSearch)
                {
                    break;
                }

                var itemStream = p.DownloadFile();
                var itemRead = new StreamReader(itemStream, System.Text.Encoding.Default);

                this.Invoke((MethodInvoker)delegate
                {
                    lblFile.Text = p.ServerItem;
                    lblFile.Refresh();

                    while (!itemRead.EndOfStream)
                    {
                        string linha = itemRead.ReadLine().ToLower();
                        if (linha.IndexOf(Texto) != -1)
                        {
                            if (lstSearchResult.Items.IndexOf(p.ServerItem) == -1)
                            {
                                lstSearchResult.Items.Add(p.ServerItem);
                                lstSearchResult.Refresh();
                                itemRead.Close();
                                break;
                            }
                        }
                    }
                    if (progressBar.Value < progressBar.Maximum)
                    {
                        progressBar.Value++;
                    }
                    progressBar.Refresh();
                });
            }
            this.Invoke((MethodInvoker)delegate
            {
                if (cancelSearch)
                {
                    lstSearchResult.Items.Clear();
                    progressBar.Value = 0;
                    lblFolder.Text = "";
                    lblFile.Text = "";
                }
                if (progressBar.Value >= progressBar.Maximum)
                {
                    progressBar.Value = 0;
                    progressBar.Refresh();
                    MessageBox.Show("Search Done!");
                    EnableButtons(true);
                }
            });
        }

        private void cbProjetos_SelectedIndexChanged(object sender, EventArgs e)
        {
            SearchText("$/"+cbProjetos.Text, "*.*", txtSearch.Text,null);
        }

        private void btnCancelar_Click(object sender, EventArgs e)
        {
            cancelSearch = true;
            EnableButtons(true);
        }

        private void btnSair_Click(object sender, EventArgs e)
        {
            btnCancelar_Click(sender, e);
            Close();
        }

        private void btnAddResults_Click(object sender, EventArgs e)
        {
            if (lstSearchResult.SelectedItems.Count == 0)
            {
                MessageBox.Show("Select some file in Result Seach!");
                return;
            }
            foreach (var linha in lstSearchResult.SelectedItems)
            {
                lstSelectedFiles.Items.Add(linha);
            }
        }

        private void btnClearResults_Click(object sender, EventArgs e)
        {
            lstSelectedFiles.Items.Clear();
        }

        private void btnExportXML_Click(object sender, EventArgs e)
        {
            if (saveFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            string fileName = saveFileDialog.FileName;

            if(File.Exists(fileName))
            {
                File.Delete(fileName);
            }

            StreamWriter export = new StreamWriter(fileName);
            export.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            export.WriteLine("<TFSFileTextSearch>");
            export.WriteLine("   <Search>");
            export.WriteLine("	    <TFSServer>"+cbServer.Text+"</TFSServer>");
            export.WriteLine("	    <TFSServerCollection>" + cbCollection.Text + "</TFSServerCollection>");
            export.WriteLine("		<Project>CDSSimco</Project>");
            export.WriteLine("		<SearchText>texto da busca</SearchText>");
            export.WriteLine("		<Folders>");
            foreach (string item in lstFolder.SelectedItems)
            {
                export.WriteLine("			   <Folder>"+item+"</Folder>");
            }
            export.WriteLine("		   </Folders>");
            export.WriteLine("		   <Results>");
            foreach (string item in lstSelectedFiles.Items)
            {
               export.WriteLine("			   <File>"+item+"</File>");
            }
            export.WriteLine("		   </Results>");
            export.WriteLine("   </Search>");
            export.WriteLine("</TFSFileTextSearch>");
            export.Flush();
            export.Close();
            MessageBox.Show("File "+fileName+" created!");
        }

        private void lstSearchResult_KeyDown(object sender, KeyEventArgs e)
        {
            ListBox list = (ListBox)sender;
            if (e.KeyCode == Keys.Delete && list.Items.Count > 0)
            {
                int atual = list.SelectedIndex;
                list.Items.RemoveAt(atual);
                if (atual < list.Items.Count)
                {
                    list.SelectedIndex = atual;
                }
                else
                {
                    list.SelectedIndex = list.Items.Count - 1;
                }
            }
            if (e.Control && e.KeyCode == Keys.T)
            {
                for (int s = 0; s < list.Items.Count; s++)
                {
                    list.SetSelected(s, true);
                }
            }
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            new frmAbout().ShowDialog();
        }
    }

    /// <summary>
    /// Class to use in thread.
    /// </summary>
    class ParametroThread
    {
        public string parametroTexto;
        public List<Item> parametroArquivos;
    }
}
